package top.lidee.common.service.twice.third.ali.impl;

import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.diagnosis.DiagnosisUtils;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AntMerchantExpandIndirectZftCreateRequest;
import com.alipay.api.request.AntMerchantExpandIndirectZftSimplecreateRequest;
import com.alipay.api.request.AntMerchantExpandIndirectZftorderQueryRequest;
import com.alipay.api.response.AntMerchantExpandIndirectZftCreateResponse;
import com.alipay.api.response.AntMerchantExpandIndirectZftSimplecreateResponse;
import com.alipay.api.response.AntMerchantExpandIndirectZftorderQueryResponse;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.lidee.common.bean.AliPayBean;
import top.lidee.common.dto.AccountInfo;
import top.lidee.common.service.StoreService;
import top.lidee.common.service.twice.applet.MtStoreCateService;
import top.lidee.common.service.twice.management.*;
import top.lidee.common.service.twice.third.ali.IndirectImageUploadService;
import top.lidee.common.service.twice.third.ali.ZftSimpleCreateService;
import top.lidee.common.to.AlipayZftCreateCommonTo;
import top.lidee.common.to.SiteInfoTo;
import top.lidee.framework.enums.CommonExceptionEnum;
import top.lidee.framework.result.GlobalCheck;
import top.lidee.framework.result.ResponseResult;
import top.lidee.repository.mapper.MtStoreMapper;
import top.lidee.repository.model.MtStore;
import top.lidee.repository.model.twice.pojo.applet.MtStoreCateEntity;
import top.lidee.repository.model.twice.pojo.management.*;
import top.lidee.utils.CopyBean;
import top.lidee.utils.MyCollUtil;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.ArrayList;

import static top.lidee.framework.constant.AlipayDefaultSettleTypeCon.*;
import static top.lidee.framework.constant.SceneConstant.ALIPAY_DEFAULT;
import static top.lidee.framework.constant.SceneConstant.TRADE_SCENE;
import static top.lidee.framework.constant.SupplierInfoConstant.*;
import static top.lidee.framework.enums.CommonExceptionEnum.HYFLXYSCTSZJWJ;
import static top.lidee.framework.enums.CommonExceptionEnum.XTNBCW_EJLMWK;

/**
 * @author 张一恒
 * @version 1.0
 * @description: ant.merchant.expand.indirect.zft.simplecreate(直付通 / 服务商二级商户标准进件)
 * @date 2024/9/26 13:55
 * 备注：
 * 1. 审核标准流程：风控审核 > 客资审核 >用户确认。
 * ○ 支付宝内部审核进件资料（风控审核和客资审核）：一般情况下系统审核3 分钟内完成，特殊行业、特殊情况（如外籍商家、进件商家名称与结算账号不一致）需人工审核，预计将在3 个工作日内完成，请耐心等待。
 * ○ 用户确认：(商家平台/API接口）进件成功后，引导二级商户签署协议，操作说明可查看 二级商户协议签署指引。
 * 2. 审核通知：
 * ○ API接口进件成功或者失败，支付宝会发送 审核消息通知 给商家。
 * ○ 商家平台进件成功或者失败不会发送审核通知。
 */
@Slf4j
@Service("zftSimpleCreateService")
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class ZftSimpleCreateServiceImpl implements ZftSimpleCreateService {

    //支付宝支付Bean
    private final AliPayBean aliPayBean;

    // 初始化SDK
    private final AlipayClient alipayClient;

    //店铺业务接口
    private final StoreService storeService;

    //中国各大银行简码表
    private final TAccountInstIdService tAccountInstIdService;

    //蚂蚁金服地区码
    private final TAreaCodeService tAreaCodeService;

    //ant.merchant.expand.indirect.image.upload(图片上传)
    private final IndirectImageUploadService indirectImageUploadService;

    //店铺主营行业分类表
    private final MtStoreCateService mtStoreCateService;

    //直付通进件记录表
    private final MtStoreAlipayInputPieceLogService mtStoreAlipayInputPieceLogService;

    //商户上传店铺二级类目特殊资质记录表
    private final MtUploadCateCertificationLogService mtUploadCateCertificationLogService;

    private final TpbAliBankAccountService tpbAliBankAccountService;
    /**
     * @param storeId
     * @param accountInfo
     * @return top.lidee.framework.result.ResponseResult
     * @description 直付通/服务商二级商户标准进件 或 通用进件 区别 ↓
     * 2. 调用进件接口将二级商户信息录入到支付宝体系中，供后续收单交易结算使用。
     * ○ （直付通/服务商二级商户标准进件接口）ant.merchant.expand.indirect.zft.simplecreate（直付通/服务商二级商户标准进件接口）：仅适用于中国大陆且进件账户与法人一致（非中国大陆账户或法人信息不一致等情况需额外上传授权函图片） 无merchant_type商户证件类型字段，企业商户或个体户没有明确的选择，没有企业或个体户入驻必填字段merchant_type。 营业执照等信息均为可选，没有身份证字段
     * ○ ant.merchant.expand.indirect.zft.create（直付通二级商户创建接口）：适用所有账户类型进件。 有merchant_type商户证件类型字段 营业执照等信息必选，有身份证字段
     * @author zhangyiheng
     * @date 2024/9/26 13:59
     */
    @Override
    @Transactional
    public ResponseResult create(Integer storeId, AccountInfo accountInfo) {
        GlobalCheck.checkManagerAdmin(accountInfo.getManagerId());

        //获取店铺证照信息
        MtStore store = storeService.getById(storeId);

        if (Objects.isNull(store) || Objects.isNull(store.getCateId())) {
            return ResponseResult.errorResult(CommonExceptionEnum.DPBCZ);
        }

        //查询支付宝结算银行账户
        TpbAliBankAccountEntity tpbAliBankAccount = tpbAliBankAccountService.getOne(Wrappers.<TpbAliBankAccountEntity>lambdaQuery()
                .eq(TpbAliBankAccountEntity::getStoreId, storeId));
        Opt.ofNullable(tpbAliBankAccount).orElseThrow(()->new BeanCreationException("无支付宝结算银行账户信息，无法进件"));

        //校验支付宝账号
        Opt.ofNullable(tpbAliBankAccount.getAlipayNum()).orElseThrow(()->new BeanCreationException(CommonExceptionEnum.ZFBZHWKBNJJ.getMsg()));

        //获取商户、店铺分类数据，主要获取店铺的二级分类数据
        MtStoreCateEntity cate = mtStoreCateService.getById(store.getCateId());

        if (Objects.isNull(cate) || Objects.isNull(cate.getSecondaryCateCode())) {
            return ResponseResult.errorResult(CommonExceptionEnum.GDPEJFLBCZ);
        }

        if (StrUtil.equalsAny(store.getStatus(), WAIT, FAIL)) {
            return ResponseResult.errorResult(CommonExceptionEnum.GDPZZXXWX_BNJJ);
        }

        //校验正在进件或已成功进件
        int count = mtStoreAlipayInputPieceLogService.count(Wrappers.<MtStoreAlipayInputPieceLogEntity>lambdaQuery()
                .eq(MtStoreAlipayInputPieceLogEntity::getStoreId, storeId)
                .eq(MtStoreAlipayInputPieceLogEntity::getState, IN_THE_INCOMING).or(wq -> wq.eq(MtStoreAlipayInputPieceLogEntity::getState, THE_INCOMING_REVIEW_IS_COMPLETE)));

        if (count > 0) {
            return ResponseResult.errorResult(CommonExceptionEnum.GDPYSJJTGZT);
        }

        //校验二级分类是否是特殊的，支付宝没有主体区分字面意思是特殊的分类就要传， 个人有可能没有特殊资质，先放行
        List<MtUploadCateCertificationLogEntity> mtUploadCateCertificationLogs = null;
        if (Objects.equals(cate.getSpecialQualification(), QUALIFYING)) {
            mtUploadCateCertificationLogs = mtUploadCateCertificationLogService.list(
                    Wrappers.<MtUploadCateCertificationLogEntity>lambdaQuery()
                            .eq(MtUploadCateCertificationLogEntity::getMerchantId, accountInfo.getManagerId())
                            .eq(MtUploadCateCertificationLogEntity::getStoreId, storeId)
                            .eq(MtUploadCateCertificationLogEntity::getCateId, cate.getCategoryId())
                            .eq(MtUploadCateCertificationLogEntity::getIsCompliance, 0)
            );
            if (!MyCollUtil.isNotEmpty(mtUploadCateCertificationLogs) && !Objects.equals(store.getPrincipalType(), SOHO)) {
                return ResponseResult.errorResult(CommonExceptionEnum.RJFLSTSHYXYTSZZTP);
            }
        }

        ResponseResult responseResult = new ResponseResult();
        //判断主体类型：0个体工商户，1企业，2个人商户
        switch (store.getPrincipalType()) {
            case SOLE_PROPRIETORSHIP:
            case ENTERPRISE:
                //个体工商和企业类型
                responseResult = create(store, cate, mtUploadCateCertificationLogs,tpbAliBankAccount);
                break;
            case SOHO:
                //个人商户： simplecreate
                responseResult = simplecreate(store, cate, mtUploadCateCertificationLogs,tpbAliBankAccount);
                break;
            default:
                break;
        }

        return responseResult;
    }

    /**
     * @return top.lidee.framework.result.ResponseResult
     * @description 直付通/服务商二级商户进件创建   详细注释在成员方法上 适用于个体工商和企业类型进件
     * @author zhangyiheng
     * @date 2024/9/26 13:59
     */
    public ResponseResult create(MtStore store, MtStoreCateEntity cate, List<MtUploadCateCertificationLogEntity> mtUploadCateCertificationLogs,TpbAliBankAccountEntity tpbAliBankAccount) {
        ResponseResult responseResult = new ResponseResult();
        MtStoreAlipayInputPieceLogEntity pieceLog = new MtStoreAlipayInputPieceLogEntity();
        pieceLog.setStoreId(store.getId());
        pieceLog.setState(IN_THE_INCOMING);
        pieceLog.setExternalId(store.getExternalId());
        try {
            // 构造请求参数以调用接口
            AntMerchantExpandIndirectZftCreateRequest request = new AntMerchantExpandIndirectZftCreateRequest();
            AlipayZftCreateCommonTo to = new AlipayZftCreateCommonTo();

            responseResult = common(to, store, cate, mtUploadCateCertificationLogs,tpbAliBankAccount);
            if (!Objects.equals(responseResult.getCode(), 0)) {
                return responseResult;
            }

            AntMerchantExpandIndirectZftCreateModel model = CopyBean.copyBean(to, AntMerchantExpandIndirectZftCreateModel.class);

            // 设置商户类型
            setTheMerchantType(model, store);

            // 设置商户证件编号
            setUpAMerchantDocumentNumber(store, model);

            // 设置商户证件类型
            setTheMerchantCertificateType(store, model);

            //region Description 设置商户联系人信息 必选
            ContactInfo contactInfo = setUpBusinessContactInformation(store);
            model.setContactInfos(Collections.singletonList(contactInfo));
            //endregion


            //region Description 设置内景照 特殊可选
            //使用当面付服务时必填。
            String imageId = setUpInteriorShots(store);
            model.setInDoorImages(Collections.singletonList(imageId));
            //endregion


            //region Description 设置商户证件图片url、 // 设置证件反面图片
            //【描述】证件反面图片。目前只有当商户类型是个人商户且使用当面付服务时才需填写
            setUpAMerchantIDImage(store, model);
            //endregion


            //region Description 设置法人名称、 设置法人身份证号
            //【描述】法人名称。非个人商户类型必填
            //【描述】法人身份证号。非个人商户类型必填
            setRequiredForNonIndividualBusinessTypes(store, model);
            //endregion


            //region Description 设置结算银行卡信息 特殊可选
            //【必选条件】结算银行卡信息，结算账号使用银行卡时必填。本业务当前只允许传入一张结算卡。个人类型商户不允许结算到银行卡
            SettleCardInfo bizCards = setUpYourBillingCardInformation(store, model.getDefaultSettleRule().getDefaultSettleType(),tpbAliBankAccount);
            model.setBizCards(Collections.singletonList(bizCards));
            //endregion


            //region Description 设置门头照 特殊可选
            //使用当面付服务时必填。
            imageId = setUpAHeadshot(store);
            model.setOutDoorImages(Collections.singletonList(imageId));
            //endregion


            //region Description 设置法人身份证正面url、设置法人身份证反面url
            //本业务接口中，如果是特殊行业必填
            setUpACorporateIDCard(store, cate, model);
            //endregion


            //region Description 设置商户站点信息 特殊可选
            //如果使用支付宝小程序支付就需要设置商户站点信息
            if (new HashSet<>(model.getService()).containsAll(Lists.newArrayList("jsapi支付", "小程序支付"))) {
                SiteInfo sites = getSiteInfo();
                model.setSites(Collections.singletonList(sites));
            }
            //endregion


            //region Description 填写值为个体工商户营业执照上的名称
            //设置目前只有个体工商户商户类型要求填入本字段
            setCertName(store, model);
            //endregion


//            // 设置客服电话
//            model.setServicePhone("0571-85022088");


            /*
            设置默认可不填
            【描述】默认可不填，认为legal_cert_no是大陆身份证。类型包括：100 大陆身份证；105 港澳居民往来内地通行证；106 台湾同胞往来大陆通行证；108 外国人居留证
            【枚举值】
                大陆身份证: 100
                港澳居民往来内地通行证: 105
                台湾同胞往来大陆通行证: 106
                外国人居留证: 108
                收起
            【示例值】100
             */
//            model.setLegalCertType("100");


            // 设置商家性质 可选
//            model.setMerchantNature("01");


            //返回
            request.setBizModel(model);
            // 第三方代调用模式下请设置app_auth_token
            // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");

            AntMerchantExpandIndirectZftCreateResponse response = alipayClient.execute(request);

/*
            { 成功示例
    "ant_merchant_expand_indirect_zft_simplecreate_response": {
        "code": "10000",
        "msg": "Success",
        "order_id": "2018012000502000000005130266"
    },
    "sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}
             */
            //获取申请单id

            String body = response.getBody();

            if (!response.isSuccess() || StrUtil.isBlank(body)) {
                String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);

                pieceLog.setState(INCOMING_ITEMS_ARE_ABNORMAL);
                pieceLog.setDiagnosisUrl(diagnosisUrl);

                log.error("店铺：{} 直付通进价申请调用失败，诊断链接：{}", store.getLicenseName(), diagnosisUrl);
                return ResponseResult.errorResult(CommonExceptionEnum.HTTP_MESSAGE_ERROR);
            }

            log.info("店铺：{} 直付通进价申请调用成功", store.getLicenseName());

            JSONObject res = JSONObject.parseObject(body);

            Object data = res.get("ant_merchant_expand_indirect_zft_create_response");
            String sign = (String) res.get("sign");
            JSONObject parsed = JSONObject.parseObject(data.toString());

            String code = (String) parsed.get("code");
            if (StrUtil.isNotBlank(code) && Objects.equals("10000", code)) {
                //支付宝初步审核成功
                String orderId = (String) parsed.get("order_id");

                //保存日志
                pieceLog.setCode(code);
                pieceLog.setMsg(parsed.get("msg").toString());
                pieceLog.setOrderId(orderId);
                pieceLog.setSign(sign);

                log.info("店铺：{} 直付通进价申请单id：{}", store.getLicenseName(), orderId);
            } else {
                //失败
                String subMsg = (String) parsed.get("sub_msg");
                String subCode = (String) parsed.get("sub_code");

                pieceLog.setCode(code);
                pieceLog.setMsg(parsed.get("msg").toString());
                pieceLog.setSubCode(subCode);
                pieceLog.setSubMsg(subMsg);
                pieceLog.setSign(sign);
                pieceLog.setState(INCOMING_ITEMS_ARE_ABNORMAL);

                log.info("店铺：{} 直付通进件失败原因：{}，错误码：{}", store.getLicenseName(), subMsg, code);
                return ResponseResult.errorResult(Integer.parseInt(code), subMsg);
            }
        } catch (Exception e) {

            pieceLog.setState(INCOMING_ITEMS_ARE_ABNORMAL);
            pieceLog.setSubMsg(e.getMessage());

            log.error("直付通/服务商二级商户标准进件处理失败：{}", e.getMessage(),e);
            throw new BeanCreationException(e.getMessage());
        } finally {
            //保存日志
            mtStoreAlipayInputPieceLogService.save(pieceLog);
        }

        return ResponseResult.ok();
    }


    /**
     * @return top.lidee.framework.result.ResponseResult
     * @description 直付通/服务商二级商户标准进件   详细注释在成员方法上 适用于个人商户（自然人）进件
     * @author zhangyiheng
     * @date 2024/9/26 13:59
     */
    public ResponseResult simplecreate(MtStore store, MtStoreCateEntity cate, List<MtUploadCateCertificationLogEntity> mtUploadCateCertificationLogs,TpbAliBankAccountEntity tpbAliBankAccount) {
        ResponseResult responseResult = new ResponseResult();
        MtStoreAlipayInputPieceLogEntity pieceLog = new MtStoreAlipayInputPieceLogEntity();
        pieceLog.setStoreId(store.getId());
        pieceLog.setState(IN_THE_INCOMING);
        pieceLog.setExternalId(store.getExternalId());
        try {
            // 构造请求参数以调用接口
            AntMerchantExpandIndirectZftSimplecreateRequest request = new AntMerchantExpandIndirectZftSimplecreateRequest();

            AlipayZftCreateCommonTo to = new AlipayZftCreateCommonTo();

            responseResult = common(to, store, cate, mtUploadCateCertificationLogs,tpbAliBankAccount);
            if (!Objects.equals(responseResult.getCode(), 0)) {
                return responseResult;
            }

            AntMerchantExpandIndirectZftSimplecreateModel model = CopyBean.copyBean(to, AntMerchantExpandIndirectZftSimplecreateModel.class);


            //region Description 设置商户联系人信息 必选
            ContactInfo contactInfo = setUpBusinessContactInformation(store);
            model.setContactInfos(contactInfo);
            //endregion


            //region Description 设置门头照 特殊可选
            //使用当面付服务时必填。
            String imageId = setUpAHeadshot(store);
            model.setOutDoorImages(imageId);
            //endregion

            //region Description 设置内景照 特殊可选
            //使用当面付服务时必填。
            imageId = setUpInteriorShots(store);
            model.setInDoorImages(imageId);
            //endregion

            //region Description 设置商户站点信息 特殊可选
            //如果使用支付宝小程序支付就需要设置商户站点信息
            if (new HashSet<>(model.getService()).containsAll(Lists.newArrayList("jsapi支付", "小程序支付"))) {
                SiteInfo sites = getSiteInfo();
                model.setSites(sites);
            }
            //endregion

            //region Description 补充证件号 可选
            //当商户类型为个人时，使用当面付收款有限额，补充这组证件信息可提额
            //备注：目前默认写死 使用营业执照号，目前仅允许个人类型商户传入本字段
            supplementaryIDNumber(store, model);
            //endregion

            //region Description 设置交易场景 可选
            //该字段影响:商户站点信息的screenshot_image字段（截图照片）
            //screenshot_image:【必选条件】当传入交易场景trade_scene，且当传入trade_scene=WAP、trade_scene=APP、trade_scene=PC时该参数必传
            setUpATradingScenario(model);
            //endregion


            // 设置商户客服电话 可选
//            model.setServicePhone(store.getPhone());
            
                        /*
            设置授权函 特殊可选
            license_auth_letter_image可选string(256)
【描述】授权函。当商户名与结算卡户名不一致。《说明函》模板参考。涉及外籍法人（这种情况上传任意能证明身份的图片）时必填，其值为使用ant.merchant.expand.indirect.image.upload上传图片得到的一串oss key。（商户类型为个体工商户时，本字段仅需上传营业执照非授权函）
             */
//            model.setLicenseAuthLetterImage("c6c0c7a1-b9d5-4e5d-b9d4-9eed39f00e65.jpg");

            // uid参数未来计划废弃，存量商户可继续使用，新商户请使用openid。请根据应用-开发配置-openid配置选择支持的字段。 可选
            // model.setInfoSourceUid("2088111122223333");

            // 设置（平替原来的info_source_uid字段 可选
            //【描述】（平替原来的info_source_uid字段，如果能拿到openId，请传本字段，原字段留空）。信息关联的openId  详情可查看 openid简介
//            model.setInfoSourceOpenId("074a1CcTG1LelxKe4xQC0zgNdId0nxi95b5lsNpazWYoCo5");

            // uid参数未来计划废弃，存量商户可继续使用，新商户请使用openid。请根据应用-开发配置-openid配置选择支持的字段。 可选
            // model.setOverseaSettleAccount("2088111122223333");

            // 设置（平替原来的oversea_settle_open_id字段 可选
            //【描述】（平替原来的oversea_settle_open_id字段，如能够获取到该场景的open_id，请传本字段，原字段留空）境外结算账号  详情可查看 openid简介
//            model.setOverseaSettleOpenId("074a1CcTG1LelxKe4xQC0zgNdId0nxi95b5lsNpazWYoCo5");

            // 设置代扣产品信息 可选
            setUpBillingProductInformation(model);


            request.setBizModel(model);
            // 第三方代调用模式下请设置app_auth_token
            // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");

            AntMerchantExpandIndirectZftSimplecreateResponse response = alipayClient.execute(request);

            /*
            { 成功示例
    "ant_merchant_expand_indirect_zft_simplecreate_response": {
        "code": "10000",
        "msg": "Success",
        "order_id": "2018012000502000000005130266"
    },
    "sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}
             */
            //获取申请单id

            String body = response.getBody();

            if (!response.isSuccess() || StrUtil.isBlank(body)) {
                String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);

                pieceLog.setState(INCOMING_ITEMS_ARE_ABNORMAL);
                pieceLog.setDiagnosisUrl(diagnosisUrl);

                log.error("店铺：{} 直付通进价申请调用失败，诊断链接：{}", store.getLicenseName(), diagnosisUrl);
                return ResponseResult.errorResult(CommonExceptionEnum.HTTP_MESSAGE_ERROR);
            }

            log.info("店铺：{} 直付通进价申请调用成功", store.getLicenseName());

            JSONObject res = JSONObject.parseObject(body);

            Object data = res.get("ant_merchant_expand_indirect_zft_simplecreate_response");
            String sign = (String) res.get("sign");
            JSONObject parsed = JSONObject.parseObject(data.toString());

            String code = (String) parsed.get("code");
            if (StrUtil.isNotBlank(code) && Objects.equals("10000", code)) {
                //支付宝初步审核成功
                String orderId = (String) parsed.get("order_id");

                //保存日志
                pieceLog.setCode(code);
                pieceLog.setMsg(parsed.get("msg").toString());
                pieceLog.setOrderId(orderId);
                pieceLog.setSign(sign);

                log.info("店铺：{} 直付通进价申请单id：{}", store.getLicenseName(), orderId);
            } else {
                //失败
                String subMsg = (String) parsed.get("sub_msg");
                String subCode = (String) parsed.get("sub_code");

                pieceLog.setCode(code);
                pieceLog.setMsg(parsed.get("msg").toString());
                pieceLog.setSubCode(subCode);
                pieceLog.setSubMsg(subMsg);
                pieceLog.setSign(sign);
                pieceLog.setState(INCOMING_ITEMS_ARE_ABNORMAL);

                log.info("店铺：{} 直付通进件失败原因：{}，错误码：{}", store.getLicenseName(), subMsg, code);
                return ResponseResult.errorResult(Integer.parseInt(code), subMsg);
            }
        } catch (Exception e) {

            pieceLog.setState(INCOMING_ITEMS_ARE_ABNORMAL);
            pieceLog.setSubMsg(e.getMessage());

            log.error("直付通/服务商二级商户标准进件处理失败：{}", e.getMessage(),e);
            throw new BeanCreationException(e.getMessage());
        } finally {
            //保存日志
            mtStoreAlipayInputPieceLogService.save(pieceLog);
        }

        return ResponseResult.ok();
    }


    /**
     * @param model
     * @param store
     * @param cate
     * @return top.lidee.framework.result.ResponseResult
     * @description 直付通二级商户创建和直付通/服务商二级商户标准进件通用字段设置
     * @author zhangyiheng
     * @date 2024/9/29 15:59
     * 设置签约支付宝账户 必选
     * 设置商户编号 必选
     * 设置商户别名 必选
     * 设置商户类别码 mcc 必选
     * 设置进件的二级商户名称 可选
     * 设置默认结算规则 必选
     * 设置商户使用服务 必选
     * 设置结算支付宝账号 特殊可选
     * 设置经营地址 特殊可选
     * 设置商户行业资质图片 特殊可选
     * 设置二级商户与服务商的签约时间 可选
     */
    private ResponseResult common(AlipayZftCreateCommonTo model, MtStore store, MtStoreCateEntity cate, List<MtUploadCateCertificationLogEntity> mtUploadCateCertificationLogs,TpbAliBankAccountEntity tpbAliBankAccount) {
        //region Description 设置签约支付宝账户 必选
        //需使用实名认证支付宝账号
        setUpAContractedAlipayAccount(model, store,tpbAliBankAccount.getAlipayNum());
        //endregion

        //region Description 设置商户编号 必选
        //由一级商户定义，保证在一级商户下唯一即可
        setUpAMerchantID(model, store);
        //endregion

        //region Description 设置商户别名 必选
        setUpABusinessAlias(model, store);
        //endregion


        //region Description 设置商户类别码 mcc 必选
        //特殊行业要按照MCC说明中的资质一栏上传辅助资质，辅助资质要在 qualifications 中上传，会有人工审核。
        if (setUpAMerchantCategoryCode(cate, model))
            return ResponseResult.errorResult(XTNBCW_EJLMWK);
        //endregion


        //region Description 设置进件的二级商户名称 可选
        setABusinessName(store, model);
        //endregion


        //region Description 设置默认结算规则 必选
        //bankCard表示结算到银行卡；alipayAccount表示结算到支付宝账号
        //根据设置结算银行卡信息字段规则：个人类型商户不允许结算到银行卡
        setAdefaultBillingRule(store, model,tpbAliBankAccount);
        //endregion


        //region Description 设置商户使用服务 必选
        //如果选择了 "jsapi支付","小程序支付" 则可以使用商家支付宝小程序支付
        //其值会影响其他字段必填性：
        //1、设置商户站点信息 ：如果选择使用了"jsapi支付","小程序支付" 需要传入站点名称、站点地址、站点小程序appid
        setUpMerchantUsageServices(model);
        //endregion

        //region Description 设置结算支付宝账号 特殊可选
        //结算账号使用支付宝账号时必填 与binding_alipay_logon_id同主体的支付宝账号即可
        setUpASettlementAlipayAccount(model, store,tpbAliBankAccount.getAlipayNum());
        //endregion


        //region 设置开票资料信息 可选
        setUpBillingProfileInformation(model);
        //endregion

        //region Description 设置经营地址 特殊可选
        //经营地址。使用当面付服务时必填。
        setUpABusinessAddress(store, model);
        //endregion


        //region Description 设置商户行业资质图片 特殊可选
        //当商户的经营类目选择了特殊行业时该字段必填
        if (setUpAMerchantIndustryQualificationImage(cate, store, model, mtUploadCateCertificationLogs))
            return ResponseResult.errorResult(HYFLXYSCTSZJWJ);
        //endregion


        //region Description 设置二级商户与服务商的签约时间 可选
        setSigningTime(model);
        //endregion

        return ResponseResult.ok();
    }

    /**
     * @param store
     * @param model
     * @return void
     * @description 填写值为个体工商户营业执照上的名称
     * 设置目前只有个体工商户商户类型要求填入本字段
     * @author zhangyiheng
     * @date 2024/9/29 18:57
     */
    private void setCertName(MtStore store, AntMerchantExpandIndirectZftCreateModel model) {
        if (Objects.equals(SOLE_PROPRIETORSHIP, store.getPrincipalType())) {
            model.setCertName(store.getLicenseName());
        }
    }

    /**
     * @param store
     * @param model
     * @return void
     * @description 设置法人名称、 设置法人身份证号
     * 【描述】法人名称。非个人商户类型必填
     * 【描述】法人身份证号。非个人商户类型必填
     * @author zhangyiheng
     * @date 2024/9/29 18:52
     */
    private void setRequiredForNonIndividualBusinessTypes(MtStore store, AntMerchantExpandIndirectZftCreateModel model) {
        if (!Objects.equals(SOHO, store.getPrincipalType())) {
            model.setLegalName(store.getContact());
            model.setLegalCertNo(store.getIdCard());
        }
    }


    /**
     * @param store
     * @param cate
     * @param model
     * @return void
     * @description 设置法人身份证正面url、设置法人身份证反面url
     * 本业务接口中，如果是特殊行业必填
     * @author zhangyiheng
     * @date 2024/9/29 18:48
     */
    private void setUpACorporateIDCard(MtStore store, MtStoreCateEntity cate, AntMerchantExpandIndirectZftCreateModel model) {
        if (Objects.equals(cate.getSpecialQualification(), QUALIFYING)) {
            //正面
            model.setLegalCertFrontImage(getImageId(store.getCardUpUrl()));
            //反面
            model.setLegalCertBackImage(getImageId(store.getCardVersaUrl()));
        }
    }

    /**
     * @param model
     * @return void
     * @description 设置商户类型
     * 【描述】商户类型： 01：企业；cert_type填写201（营业执照）；cert_no填写营业执照号；
     * 02：事业单位：cert_type填写218（事业单位法人证书）；cert_no填写事业单位法人证书编号；
     * 03：民办非企业组织：cert_type填写204（民办非企业登记证书）；cert_no填写民办非企业登记证书编号；
     * 04：社会团体：cert_type填写206（社会团体法人登记证书）；cert_no填写社会团体法人登记证书编号；
     * 05：党政及国家机关：cert_type填写219（党政机关批准设立文件/行政执法主体资格证）；cert_no填写党政机关批准设立文件/行政执法主体资格证编号； 06：个人商户：cert_type填写100（个人身份证）；cert_no填写个人身份证号码；
     * 07：个体工商户：cert_type填写201（营业执照）；cert_no填写营业执照编号；
     * 【枚举值】
     * 企业: 01
     * 事业单位: 02
     * 民办非企业组织: 03
     * 社会团体: 04
     * 党政及国家机关: 05
     * 个人商户: 06
     * 个体工商户: 07
     * @author zhangyiheng
     * @date 2024/9/29 17:22
     */
    private void setTheMerchantType(AntMerchantExpandIndirectZftCreateModel model, MtStore store) {
        switch (store.getPrincipalType()) {
            case SOLE_PROPRIETORSHIP: //个体工商户
                model.setMerchantType("07");
                break;
            case ENTERPRISE: //企业
                model.setMerchantType("01");
                break;
            case SOHO: //个人商户
                model.setMerchantType("06");
                break;
            default:
                throw new BeanCreationException("主体类型错误");
        }

    }

    /**
     * @param store
     * @param model
     * @return void
     * @description 1【描述】商户证件图片url，本业务接口中，如果是特殊行业必填；使用当面付服务时，非个人必填，个人结算到卡时必填。其值为使用ant.merchant.expand.indirect.image.upload上传图片得到的一串oss key。
     * 2【描述】证件反面图片。目前只有当商户类型是个人商户且使用当面付服务时才需填写
     * @author zhangyiheng
     * @date 2024/9/29 17:54
     */
    private void setUpAMerchantIDImage(MtStore store, AntMerchantExpandIndirectZftCreateModel model) {
        switch (store.getPrincipalType()) {
            case SOLE_PROPRIETORSHIP: // 个体工商户：营业执照
            case ENTERPRISE: // 企业；营业执照
                model.setCertImage(getImageId(store.getLicense()));
                break;
            case SOHO: //个人商户：个人身份证正面和反面
                model.setCertImage(getImageId(store.getCardUpUrl()));
                //【描述】证件反面图片。目前只有当商户类型是个人商户且使用当面付服务时才需填写
                model.setCertImageBack(getImageId(store.getCardVersaUrl()));
                break;
            default:
                throw new BeanCreationException("主体类型错误");
        }
    }

    /**
     * @param store
     * @param model
     * @return void
     * @description 【描述】商户证件类型，按商户类型merchant_type的说明提供对应的证件类型
     * 【枚举值】
     * 营业执照: 201
     * 事业单位法人证书: 218
     * 民办非企业登记证书: 204
     * 社会团体法人登记证书: 206
     * 党政机关批准设立文件/行政执法主体资格证: 219
     * 个人身份证: 100
     * 【示例值】201
     * @author zhangyiheng
     * @date 2024/9/29 17:34
     */
    private void setTheMerchantCertificateType(MtStore store, AntMerchantExpandIndirectZftCreateModel model) {
        switch (store.getPrincipalType()) {
            case SOLE_PROPRIETORSHIP: // 个体工商户：cert_type填写201（营业执照）；cert_no填写营业执照编号；
                model.setCertType("201");
                break;
            case ENTERPRISE: // 企业；cert_type填写201（营业执照）；cert_no填写营业执照号；
                model.setCertType("201");
                break;
            case SOHO: //个人商户：cert_type填写100（个人身份证）；cert_no填写个人身份证号码；
                model.setCertType("100");
                break;
            default:
                throw new BeanCreationException("主体类型错误");
        }
    }

    /**
     * @param store
     * @param model
     * @return void
     * @description 设置商户证件编号
     * 【描述】商户证件编号，按商户类型merchant_type的说明提供对应的证件编号
     * @author zhangyiheng
     * @date 2024/9/29 17:32
     */
    private void setUpAMerchantDocumentNumber(MtStore store, AntMerchantExpandIndirectZftCreateModel model) {
        switch (store.getPrincipalType()) {
            case SOLE_PROPRIETORSHIP: // 个体工商户：cert_type填写201（营业执照）；cert_no填写营业执照编号；
                model.setCertNo(store.getCreditCode());
                break;
            case ENTERPRISE: // 企业；cert_type填写201（营业执照）；cert_no填写营业执照号；
                model.setCertNo(store.getCreditCode());
                break;
            case SOHO: //个人商户：cert_type填写100（个人身份证）；cert_no填写个人身份证号码；
                model.setCertNo(store.getIdCard());
                break;
            default:
                throw new BeanCreationException("主体类型错误");
        }
    }

    /**
     * @param model
     * @return void
     * @description 设置交易场景
     * 【描述】交易场景；
     * 【枚举值】
     * 小程序支付场景: TINY_APP
     * H5场景: WAP
     * 线下当面付场景: OFFLINE
     * APP支付场景: APP
     * 网站支付场景: PC
     * 收起
     * 【示例值】["TINY_APP"]
     * @author zhangyiheng
     * @date 2024/9/29 13:03
     */
    private void setUpATradingScenario(AntMerchantExpandIndirectZftSimplecreateModel model) {
        model.setTradeScene(TRADE_SCENE);
    }

    /**
     * @param model
     * @return void
     * @description 设置二级商户与服务商的签约时间
     * 【示例值】2015-04-15
     * @author zhangyiheng
     * @date 2024/9/29 13:01
     */
    private void setSigningTime(AlipayZftCreateCommonTo model) {
        model.setSignTimeWithIsv(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
    }

    /**
     * @param cate
     * @param model
     * @return boolean
     * @description 设置商户类别码 mcc
     * 【描述】商户类别码 mcc，可查看 进件MCC与资质要求 202212.xlsx
     * ，特殊行业要按照MCC说明中的资质一栏上传辅助资质，辅助资质要在 qualifications 中上传，会有人工审核。
     * 【示例值】B0007
     * @author zhangyiheng
     * @date 2024/9/29 12:59
     */
    private boolean setUpAMerchantCategoryCode(MtStoreCateEntity cate, AlipayZftCreateCommonTo model) {
        if (!Objects.isNull(cate)) {
            model.setMcc(cate.getSecondaryCateCode());
        } else {
            return true;
        }
        return false;
    }

    /**
     * @param store
     * @return void
     * @description 设置内景照
     * 【描述】内景照，使用当面付服务时必填。其值为使用ant.merchant.expand.indirect.image.upload上传图片得到的一串oss key。
     * @author zhangyiheng
     * @date 2024/9/29 12:57
     */
    private String setUpInteriorShots(MtStore store) {
        if (StrUtil.isNotBlank(store.getInteriorUrl())) {
            return getImageId(store.getInteriorUrl());
        }
        return null;
    }

    /**
     * @param store
     * @return void
     * @description 设置门头照
     * 【描述】门头照，使用当面付服务时必填。其值为使用ant.merchant.expand.indirect.image.upload上传图片得到的一串oss key。
     * @author zhangyiheng
     * @date 2024/9/29 12:56
     */
    private String setUpAHeadshot(MtStore store) {
        if (StrUtil.isNotBlank(store.getDoorPhotographUrl())) {
            return getImageId(store.getDoorPhotographUrl());
        }
        return null;
    }

    /**
     * @param model
     * @param store
     * @return void
     * @description 结算支付宝账号
     * 【描述】结算支付宝账号，结算账号使用支付宝账号时必填，本字段指定交易资金结算的具体支付宝账号，与binding_alipay_logon_id同主体的支付宝账号即可
     * @author zhangyiheng
     * @date 2024/9/29 12:53
     */
    private void setUpASettlementAlipayAccount(AlipayZftCreateCommonTo model, MtStore store,String alipayNum) {
        String defaultSettleType = model.getDefaultSettleRule().getDefaultSettleType();
        if (Objects.equals("alipayAccount", defaultSettleType)) {
            model.setAlipayLogonId(alipayNum);
        }
    }


    /**
     * @param model
     * @return void
     * @description 设置商户使用服务
     * service必选string[](200)
     * 【描述】商户使用服务，可选值有：当面付、jsapi支付、app支付、wap支付、电脑支付、预授权支付、商户代扣、小程序支付、订单码支付。其值会影响其他字段必填性，详见其他字段描述
     * 【示例值】["当面付"]
     * @author zhangyiheng
     * @date 2024/9/29 12:51
     */
    private void setUpMerchantUsageServices(AlipayZftCreateCommonTo model) {
        model.setService(ALIPAY_DEFAULT);
    }

    /**
     * @param store
     * @param model
     * @return void
     * @description 设置进件的二级商户名称
     * 【描述】进件的二级商户名称。一般情况下要与证件的名称相同。个体工商户类型可以放宽到法人名称
     * @author zhangyiheng
     * @date 2024/9/29 12:49
     */
    private void setABusinessName(MtStore store, AlipayZftCreateCommonTo model) {
        if (StrUtil.equalsAny(store.getPrincipalType(), SOLE_PROPRIETORSHIP,SOHO)) {
            store.setLicenseName(StrUtil.isBlank(store.getLicenseName()) ? store.getContact() : store.getLicenseName());
        }
        model.setName(store.getLicenseName());
    }

    /**
     * @param store
     * @return void
     * @description 设置商户联系人信息
     * 【描述】商户联系人信息。在本业务中，ContactInfo对象中联系人姓名、手机号必填，其他选填
     * @author zhangyiheng
     * @date 2024/9/29 12:47
     */
    private ContactInfo setUpBusinessContactInformation(MtStore store) {
        ContactInfo contactInfos = new ContactInfo();
        contactInfos.setIdCardNo(store.getIdCard());
//            contactInfos.setPhone(store.getPhone());
        contactInfos.setName(store.getContact());
        contactInfos.setMobile(store.getPhone());
//            contactInfos.setEmail("user@domain.com");
        return contactInfos;
    }


    /**
     * @param model
     * @param store
     * @return void
     * @description 设置商户别名
     * * 【描述】商户别名。支付宝收银台及账单中的商户名称会展示此处设置的别名。如果涉及支付宝APP内的支付，支付结果页也会展示该别名；如果涉及线下当面付场景，请填写线下店铺名称
     * @author zhangyiheng
     * @date 2024/9/29 12:46
     */
    private void setUpABusinessAlias(AlipayZftCreateCommonTo model, MtStore store) {
        model.setAliasName(store.getName());
    }

    /**
     * @param model
     * @param store
     * @return void
     * @description 设置商户编号
     * 【描述】商户编号，由一级商户定义，保证在一级商户下唯一即可
     * 【示例值】105290059990194
     * @author zhangyiheng
     * @date 2024/9/29 12:45
     */
    private void setUpAMerchantID(AlipayZftCreateCommonTo model, MtStore store) {
        model.setExternalId(store.getExternalId());
    }

    /**
     * @param model
     * @param store
     * @return void
     * @description 设置签约支付宝账户
     * 【描述】签约支付宝账户。需使用实名认证支付宝账号，使用该支付宝账号签约直付通二级商户及后续服务，商户主体与该支付宝账号主体相同
     * 【示例值】asdf@163.com
     * @author zhangyiheng
     * @date 2024/9/29 12:44
     */
    private void setUpAContractedAlipayAccount(AlipayZftCreateCommonTo model, MtStore store,String alipayNum) {
        model.setBindingAlipayLogonId(alipayNum);
    }


    /**
     * @param model
     * @return void
     * @description 设置代扣产品信息 可选
     * @author zhangyiheng
     * @date 2024/9/29 11:47
     */
    private void setUpBillingProductInformation(AntMerchantExpandIndirectZftSimplecreateModel model) {
        ZFTWithholdingInfo zftWithholdingInfo = new ZFTWithholdingInfo();
        /*
        【描述】代扣产品业务模式；
           【枚举值】
           通用扣款: GENERAL_WITHHOLDING_P
           周期性扣款: CYCLE_PAY_AUTH_P
           单次授权: ONE_TIME_AUTH_P
           免密支付: NOPWD_P
           收起
           【示例值】GENERAL_WITHHOLDING_P
         */
        zftWithholdingInfo.setWithholdingServiceFeatureName("NOPWD_P");
        /*
        sign_scene可选string(64)
            【描述】代扣签约场景码
            【示例值】DEFAULT
         */
        zftWithholdingInfo.setSignScene("DEFAULT");
        model.setZftWithholdingInfo(zftWithholdingInfo);
    }


    /**
     * @param store
     * @param model
     * @return void
     * @description 补充证件号，与additional_cert_type+additional_cert_image同时提供。
     * 当商户类型为个人时，使用当面付收款有限额，补充这组证件信息可提额
     * 目前仅允许个人类型商户传入本字段
     * 设置补充证件号
     * 设置补充证件类型
     * 设置补充证件图片
     * 备注：目前默认写死 营业执照号
     * @author zhangyiheng
     * @date 2024/9/29 11:41
     */
    private void supplementaryIDNumber(MtStore store, AntMerchantExpandIndirectZftSimplecreateModel model) {
        if (Objects.equals(SOHO, store.getPrincipalType())) {
            // 设置补充证件号
            /*
            【描述】补充证件号，与additional_cert_type+additional_cert_image同时提供。当商户类型为个人时，使用当面付收款有限额，补充这组证件信息可提额。目前仅允许个人类型商户传入本字段。
            【示例值】9133010608210550XR
             */
            model.setAdditionalCertNo(store.getCreditCode());

            // 设置补充证件类型
            /*
            【描述】补充证件类型，与additional_cert_no+additional_cert_image同时提供。可选值有201（营业执照号）、204（民办非企业登记证书）、206（社会团体法人登记证书）、218（事业单位法人证书）、219（党政机关批准设立文件/行政执法主体资格证）。
             */
            model.setAdditionalCertType("201");

            // 设置补充证件图片
            /*
            【描述】补充证件图片，与additional_cert_no、additional_cert_type同时提供。当商户类型为个人时，使用当面付收款有限额，补充这组证件信息可提额。目前仅允许个人类型商户传入。其值为使用ant.merchant.expand.indirect.image.upload上传图片得到的一串oss key。
             */
            String imageId = getImageId(store.getLicense());
            model.setAdditionalCertImage(imageId);
        }
    }

    /**
     * @param cate
     * @param store
     * @param model
     * @return boolean
     * @description 设置商户行业资质图片
     * 【描述】商户行业资质图片，当商户的经营类目选择了特殊行业时该字段必填，需要特殊行业资质文件。每项行业资质信息中，industry_qualification_type和industry_qualification_image均必填。
     * @author zhangyiheng
     * @date 2024/9/29 11:33
     */
    private boolean setUpAMerchantIndustryQualificationImage(MtStoreCateEntity cate, MtStore store, AlipayZftCreateCommonTo model, List<MtUploadCateCertificationLogEntity> mtUploadCateCertificationLogs) {
        if (Objects.equals(store.getPrincipalType(), SOHO) && !MyCollUtil.isNotEmpty(mtUploadCateCertificationLogs)) {
            return false;
        }

        if (Objects.equals(QUALIFYING, cate.getSpecialQualification())) {
            List<IndustryQualificationInfo> qualifications = new ArrayList<IndustryQualificationInfo>();
            for (MtUploadCateCertificationLogEntity mtUploadCateCertificationLog : mtUploadCateCertificationLogs) {
                IndustryQualificationInfo qualifications0 = new IndustryQualificationInfo();
                //【描述】商户行业资质类型
                qualifications0.setIndustryQualificationType(mtUploadCateCertificationLog.getIndustryQualificationType());
                //【描述】商户行业资质图片。其值为通过ant.merchant.expand.indirect.image.upload上传图片得到的image_id
                if (Objects.isNull(mtUploadCateCertificationLog.getImageUrl())) {
                    return true;
                }
                String imageId = getImageId(mtUploadCateCertificationLog.getImageUrl());
                qualifications0.setIndustryQualificationImage(imageId);
                qualifications.add(qualifications0);
            }

            model.setQualifications(qualifications);
        }
        return false;
    }

    /**
     * @return void
     * @description 设置商户站点信息
     * 【描述】商户站点信息，包括网站、app、小程序。商户使用服务包含电脑支付、wap支付时，必须填充一个类型为01(网站)的SiteInfo对象，site_type/site_url/site_name必填；当包含app支付时，必须至少填充类型为02(APP)或06(支付宝小程序)中一种类型的SiteInfo对象，site_type/site_name必填；当包含jsapi支付时，必须填充一个类型为06(支付宝小程序)的SiteInfo对象；
     * @author zhangyiheng
     * @date 2024/9/29 11:05
     */
    private SiteInfo getSiteInfo() {
        SiteInfo sites = new SiteInfo();
        //【描述】网站类型 必选
        sites.setSiteType("06");
        /*
            【描述】站点地址
            【必选条件】当传入service，且包含jsapi支付时，sites的site_type=06, site_url必填
            特殊可选
        */
        sites.setSiteUrl("https://xxx.alipay.com");
        /*
            【描述】站点名称
            【必选条件】当传入service，且包含jsapi支付、小程序支付时，sites的site_type=06, site_name必填
        */
        sites.setSiteName("XXX网站");
        /*
            【描述】小程序appId; 当传入service，且包含jsapi支付时，sites的site_type=06, tiny_app_id必填。
            【必选条件】当传入service，且包含jsapi支付时，sites的site_type=06, tiny_app_id必填
            特殊可选
        */
        sites.setTinyAppId("xxx105652035");

         /*
            【描述】截图照片；当传入交易场景trade_scene，且当传入trade_scene=WAP、trade_scene=APP、trade_scene=PC时该参数必传
            【必选条件】当传入交易场景trade_scene，且当传入trade_scene=WAP、trade_scene=APP、trade_scene=PC时该参数必传
            特殊可选
        */
//      sites.setScreenshotImage("c6c0c7a1-b9d5-4e5d-b9d4-9eed39f00e65.jpg");


        //【描述】网站域名 可选
//            sites.setSiteDomain("www.alipay.com");

        //【描述】备注说明 可选
//            sites.setRemark("备注说明");
        //【描述】授权函照片 可选
//            sites.setAuthLetterImage("c6c0c7a1-b9d5-4e5d-b9d4-9eed39f00e65.jpg");

        //【描述】应用市场 可选
//            sites.setMarket("豌豆荚");
//            sites.setPassword("测试密码");
        // 【描述】下载地址 可选
//            sites.setDownload("https://itunes.apple.com/cn/app/id333206289?mt=8");
        //【描述】ICP备案主体信息服务名称 可选
//            sites.setIcpServiceName("支付宝");
        //【描述】备注说明图片 可选
//            sites.setRemarkImage("c6c0c7a1-b9d5-4e5d-b9d4-9eed39f00e65.jpg");
//            sites.setAccount("测试账号");
        //【描述】ICP备案/许可证号 可选
//        sites.setIcpNo("沪ICP备15027489号-2");
        //【描述】上架状态； 可选
//        sites.setStatus("ONLINE");

        return sites;
    }


    /**
     * 设置默认结算规则
     * 【描述】默认结算类型，可选值有bankCard/alipayAccount。bankCard表示结算到银行卡；alipayAccount表示结算到支付宝账号
     *
     * @param store
     * @param model
     */
    private void setAdefaultBillingRule(MtStore store, AlipayZftCreateCommonTo model,TpbAliBankAccountEntity tpbAliBankAccount) {
        DefaultSettleRule defaultSettleRule = new DefaultSettleRule();
        //设置结算银行卡信息时 个人类型商户不允许结算到银行卡
        if (!Objects.equals(SOHO, store.getPrincipalType())) {
            switch (tpbAliBankAccount.getAlipayDefaultSettleType()) {
                case ALIPAYACCOUNT: //结算到支付宝账号: alipayAccount
                    defaultSettleRule.setDefaultSettleType("alipayAccount");
                    defaultSettleRule.setDefaultSettleTarget(tpbAliBankAccount.getAlipayNum());
                    break;
                case BANKCARD: //结算到银行卡: bankCard
                    defaultSettleRule.setDefaultSettleType("bankCard");
                    defaultSettleRule.setDefaultSettleTarget(tpbAliBankAccount.getBankCardNumber());
                    break;
                default:
                    break;
            }
        } else {
            defaultSettleRule.setDefaultSettleType("alipayAccount");
            defaultSettleRule.setDefaultSettleTarget(tpbAliBankAccount.getAlipayNum());
        }
        model.setDefaultSettleRule(defaultSettleRule);
    }

    /**
     * 设置开票资料信息 可选
     *
     * @param model
     */
    private void setUpBillingProfileInformation(AlipayZftCreateCommonTo model) {
//        MerchantInvoiceInfo invoiceInfo = new MerchantInvoiceInfo();
//        invoiceInfo.setMailTelephone("057162288888");
//        invoiceInfo.setTaxPayerQualification("01");
//        invoiceInfo.setAddress("浙江省杭州市西湖区西溪路蚂蚁金服");
//        invoiceInfo.setAcceptElectronic(false);
//        invoiceInfo.setTelephone("057162288888");
//        invoiceInfo.setTitle("蚂蚁金服（杭州）信息技术有限公司");
//        invoiceInfo.setMailName("张三");
//        invoiceInfo.setAutoInvoice(true);
//        invoiceInfo.setTaxPayerValid("19981011");
//        invoiceInfo.setTaxNo("51010482542598631219");
//        invoiceInfo.setBankName("中国银行");
//        AddressInfo mailAddress = new AddressInfo();
//        mailAddress.setAddress("万塘路18号黄龙时代广场B座");
//        mailAddress.setDistrictCode("371002");
//        mailAddress.setLatitude("60.270001");
//        mailAddress.setCityCode("371000");
//        mailAddress.setPoiid("B0FFIVU189");
//        mailAddress.setProvinceCode("370000");
//        mailAddress.setLongitude("120.760001");
//        invoiceInfo.setMailAddress(mailAddress);
//        invoiceInfo.setBankAccount("1234567812345678123");
//        model.setInvoiceInfo(invoiceInfo);
    }

    /**
     * @param store
     * @param model
     * @return void
     * @description 设置经营地址
     * business_address特殊可选AddressInfo
     * 【描述】经营地址。使用当面付服务时必填。地址对象中省、市、区、地址必填，其余选填
     * @author zhangyiheng
     * @date 2024/9/29 12:56
     */
    private void setUpABusinessAddress(MtStore store, AlipayZftCreateCommonTo model) {
        AddressInfo businessAddress = new AddressInfo();
        //address｜地址必选string(256) 必选
        businessAddress.setAddress(store.getAddress());

        //区县 必选
        TAreaCodeEntity county = tAreaCodeService.getOne(Wrappers.<TAreaCodeEntity>lambdaQuery()
                .eq(StrUtil.isNotBlank(store.getCounty()), TAreaCodeEntity::getAreaName, store.getCounty())
                .or(wq -> wq.eq(TAreaCodeEntity::getAbbreviation, store.getCounty())));
        if (!Objects.isNull(county)) {
            //district_code｜区县编码必选string(10)
            businessAddress.setDistrictCode(county.getAreaCode());
        }

        //城市 必选
        TAreaCodeEntity city = tAreaCodeService.getOne(Wrappers.<TAreaCodeEntity>lambdaQuery()
                .eq(StrUtil.isNotBlank(store.getCity()), TAreaCodeEntity::getAreaName, store.getCity())
                .or(wq -> wq.eq(TAreaCodeEntity::getAbbreviation, store.getCity())));
        if (!Objects.isNull(city)) {
            //city_code｜城市编码必选string(10)
            businessAddress.setCityCode(city.getAreaCode());
        }

        //省份 必选
        TAreaCodeEntity province = tAreaCodeService.getOne(Wrappers.<TAreaCodeEntity>lambdaQuery()
                .eq(StrUtil.isNotBlank(store.getProvince()), TAreaCodeEntity::getAreaName, store.getProvince())
                .or(wq -> wq.eq(TAreaCodeEntity::getAbbreviation, store.getProvince())));
        if (!Objects.isNull(province)) {
            //province_code｜省份编码必选string(10)
            businessAddress.setProvinceCode(province.getAreaCode());
        }

        //可选
//            //poiid｜高德poiid可选string(16)
//            businessAddress.setPoiid("B0FFIVU189");
//            //latitude｜纬度可选string(10)
//            businessAddress.setLatitude("60.270001");
//            //type｜地址类型可选string(64)
//            //【描述】地址类型。取值范围：BUSINESS_ADDRESS：经营地址（默认）
//            businessAddress.setType("BUSINESS_ADDRESS");
//            //latitude｜纬度可选string(10)
//            businessAddress.setLongitude("120.760001");
        model.setBusinessAddress(businessAddress);
    }


    /**
     * @param store
     * @return void
     * @description 设置结算银行卡信息
     * biz_cards特殊可选SettleCardInfo
     * 【描述】结算银行卡信息，结算账号使用银行卡时必填。本业务当前只允许传入一张结算卡。个人类型商户不允许结算到银行卡
     * 【必选条件】结算银行卡信息，结算账号使用银行卡时必填。本业务当前只允许传入一张结算卡。个人类型商户不允许结算到银行卡
     * @author zhangyiheng
     * @date 2024/9/29 12:54
     */
    private SettleCardInfo setUpYourBillingCardInformation(MtStore store, String defaultSettleType,TpbAliBankAccountEntity tpbAliBankAccount) {
        //【必选条件】结算银行卡信息，结算账号使用银行卡时必填。本业务当前只允许传入一张结算卡。个人类型商户不允许结算到银行卡
        //本业务当前只允许传入一张结算卡。个人类型商户不允许结算到银行卡
        if (!Objects.equals(SOHO, store.getPrincipalType())
                && Objects.equals(BANKCARD, tpbAliBankAccount.getAlipayDefaultSettleType())
                && Objects.equals("bankCard", defaultSettleType)
                && !Objects.isNull(tpbAliBankAccount.getBankCardNumber())) {
            SettleCardInfo bizCards = new SettleCardInfo();

            TAccountInstIdEntity inst = tAccountInstIdService.getById(tpbAliBankAccount.getAccountInstId());
            //account_inst_name｜银行名称
            bizCards.setAccountInstName(inst.getBankName());
            //account_inst_id｜开户行简称缩写必选string(10)
            bizCards.setAccountInstId(inst.getBankCode());

            /*
            account_type｜卡类型必选string(64)
            【描述】卡类型
            借记卡-DC
            信用卡-CC
            【枚举值】
            借记卡: DC
            信用卡: CC
             */
            switch (tpbAliBankAccount.getAccountType()) {
                case DC:
                    bizCards.setAccountType("DC");
                    break;
                case CC:
                    bizCards.setAccountType("CC");
                    break;
                default:
                    break;
            }
            /*
            usage_type｜账号使用类型必选string(64)
            【描述】账号使用类型
            对公-01
            对私-02
            【枚举值】
            对公: 01
            对私: 02
             */
            switch (tpbAliBankAccount.getUsageType()) {
                case TO_THE_PUBLIC:
                    bizCards.setAccountType("01");
                    break;
                case TO_THE_PRIVATE:
                    bizCards.setAccountType("02");
                    break;
                default:
                    break;
            }
            //account_holder_name｜卡户名必选string(64)
            bizCards.setAccountHolderName(tpbAliBankAccount.getBankCardHolder());
            //account_inst_province｜开户行所在地-省必选string(10)
            bizCards.setAccountInstProvince(tpbAliBankAccount.getAccountInstProvince());
            /*
            account_inst_city｜开户行所在地-市必选string(10)
            【描述】开户行所在地-市
             */
            bizCards.setAccountInstCity(tpbAliBankAccount.getAccountInstCity());

            //account_no｜银行卡号必选string(20)
            bizCards.setAccountNo(tpbAliBankAccount.getBankCardNumber());

            //account_branch_name｜开户支行名必选string(64)
            bizCards.setAccountBranchName(tpbAliBankAccount.getAccountBranchName());

            //bank_code｜联行号可选string(64)
            //bizCards.setBankCode(store.getBankCardNo());
            return bizCards;
        }
        return null;
    }

    /**
     * @param imageUrl {
     *                 "ant_merchant_expand_indirect_image_upload_response": {
     *                 "code": "10000",
     *                 "msg": "Success",
     *                 "image_id": "a5d373f6-3e79-405f-9993-fb7ea051c372.jpg"
     *                 },
     *                 "sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
     *                 }
     */
    private String getImageId(String imageUrl) {
        //获取文件名
        String imagName = getImagName(imageUrl);
        Optional<MediaType> mediaType = MediaTypeFactory.getMediaType(imagName);
        //获取文件字节流
        byte[] bytes = indirectImageUploadService.urlOfBytes(imageUrl, mediaType.orElse(MediaType.IMAGE_PNG));
        //请求获取标识 ImageId
        String body = indirectImageUploadService.load(imagName.substring(imagName.lastIndexOf(".") + 1), bytes, imagName);

        JSONObject jsonObject = JSONObject.parseObject(body);
        Object code = jsonObject.get("code");

        if (Objects.equals(code, "10000")) {
            return jsonObject.get("image_id").toString();
        } else {
            throw new BeanCreationException(jsonObject.get("sub_msg").toString());
        }
    }

    /**
     * 获取文件名
     *
     * @param url
     * @return
     */
    private String getImagName(String url) {
        for (int i = 0; i < 3; i++) {
            url = url.substring(url.indexOf("/") + 1);
        }
        return url;
    }

    /**
     * @param charset
     * @param bizContent
     * @param msgAppId
     * @param utcTimestamp
     * @param version
     * @param signType
     * @param notifyType
     * @param notifyId
     * @param appId
     * @param sign
     * @param msgMethod
     * @param msgType
     * @param encryptType
     * @param notifyTime
     * @param authAppId
     * @return java.lang.String
     * @description 直付通/服务商二级商户进件审核通过消息
     * @author zhangyiheng
     * @date 2024/9/30 12:37
     */
    @Override
    @Transactional
    public String alipaySuccessInfo(String charset, String bizContent, String msgAppId, String utcTimestamp, String version, String signType, String notifyType, String notifyId, String appId, String sign, String msgMethod, String msgType, String encryptType, String notifyTime, String authAppId) {
        /**
         * 对报文进行验签
         * @param content 验签内容
         * @param sign 签名值
         * @param publicKey 支付宝公钥
         * @param charset 验签字符集
         * @param signType 签名算法
         * @return 验签结果。true: 验签通过； false: 验签失败
         * @throws AlipayApiException
         */
        try {
            String fail = signatureVerification(charset, bizContent, utcTimestamp, version, signType, notifyId, appId, sign, msgMethod);
            if (fail != null) return fail;


            JSONObject parsed = JSONObject.parseObject(bizContent);
            String orderId = (String) parsed.get("order_id");
            String smid = (String) parsed.get("smid");
            if (StrUtil.isBlank(smid)) {
                return "fail";
            }
            String external_id = (String) parsed.get("external_id");

            String card_alias_no = (String) parsed.get("card_alias_no");
            String memo = (String) parsed.get("memo");

            //每次调用进件接口，均视为一次独立的申请，完成基础校验后会生成一个新的申请单号
            MtStoreAlipayInputPieceLogEntity log = mtStoreAlipayInputPieceLogService.getOne(Wrappers.<MtStoreAlipayInputPieceLogEntity>lambdaQuery()
                    .eq(MtStoreAlipayInputPieceLogEntity::getOrderId, orderId));

            if (!Objects.equals(external_id, log.getExternalId())) {
                return "fail";
            }

            //保存日志修改状态，删除以前的失败日志
            log.setNotifyId(notifyId);
            log.setUtcTimestamp(utcTimestamp);
            log.setMsgMethod(msgMethod);
            log.setAppId(appId);
            log.setMsgType(msgType);
            log.setMsgAppId(msgAppId);
            log.setVersion(version);
            log.setBizContent(bizContent);
            log.setInformSign(sign);
            log.setSignType(signType);
            log.setEncryptType(encryptType);
            log.setCharset(charset);
            log.setNotifyType(notifyType);
            log.setNotifyTime(notifyTime);
            log.setAuthAppId(authAppId);
            log.setSmid(smid);
            log.setCardAliasNo(card_alias_no);
            log.setMemo(memo);
            log.setState(THE_INCOMING_REVIEW_IS_COMPLETE);
            mtStoreAlipayInputPieceLogService.saveOrUpdate(log);

            //删除之前失败的数据
            mtStoreAlipayInputPieceLogService.remove(Wrappers.<MtStoreAlipayInputPieceLogEntity>lambdaQuery()
                    .eq(MtStoreAlipayInputPieceLogEntity::getExternalId, log.getExternalId())
                    .eq(MtStoreAlipayInputPieceLogEntity::getState, INCOMING_ITEMS_ARE_ABNORMAL)
                    .isNull(MtStoreAlipayInputPieceLogEntity::getSmid));
        } catch (Exception e) {
            log.error("直付通/服务商二级商户进件审核通过消息处理失败：{}", e.getMessage(),e);
            throw new BeanCreationException(e.getMessage());
        }
            /*
            幂等处理
            由于消息存在重试机制（见投递重试策略），同一笔消息（相同 notify_id）可能多次发送（网络原因、商家服务器原因、或者商家接收处理成功但并未按要求返回 success 字符串等），消息接收方需要对同一个 notifyId 的多次消息投递实现幂等处理。若之前相同的 notify_id 已处理成功直接返回 success 字符串即可。
             */
        return "success";
    }

    private String signatureVerification(String charset, String bizContent, String utcTimestamp, String version, String signType, String notifyId, String appId, String sign, String msgMethod) throws AlipayApiException {
        //验签：
        String content = "app_id=" + appId + "&"
                + "biz_content=" + bizContent + "&"
                + "charset=" + charset + "&"
                + "msg_method=" + msgMethod + "&"
                + "notify_id=" + notifyId + "&"
                + "utc_timestamp=" + utcTimestamp + "&"
                + "version=" + version + "&";


        boolean rsaed = AlipaySignature.rsaCheck(content, sign, aliPayBean.getPublicKey(), charset, signType);

        if (!rsaed) {
            return "fail";
        }
        return null;
    }

    /**
     * @param charset
     * @param bizContent
     * @param msgAppId
     * @param utcTimestamp
     * @param version
     * @param signType
     * @param notifyType
     * @param notifyId
     * @param appId
     * @param sign
     * @param msgMethod
     * @param msgType
     * @param encryptType
     * @param notifyTime
     * @param authAppId
     * @return java.lang.String
     * @description 直付通/服务商二级商户进件拒绝消息
     * @author zhangyiheng
     * @date 2024/9/30 14:02
     */
    @Override
    @Transactional
    public String alipayFailInfo(String charset, String bizContent, String msgAppId, String utcTimestamp, String version, String signType, String notifyType, String notifyId, String appId, String sign, String msgMethod, String msgType, String encryptType, String notifyTime, String authAppId) {
        try {
            String fail = signatureVerification(charset, bizContent, utcTimestamp, version, signType, notifyId, appId, sign, msgMethod);
            if (fail != null) return fail;

            JSONObject parsed = JSONObject.parseObject(bizContent);
            String orderId = (String) parsed.get("order_id");

            String external_id = (String) parsed.get("external_id");

            String reason = (String) parsed.get("reason");

            //每次调用进件接口，均视为一次独立的申请，完成基础校验后会生成一个新的申请单号。
            MtStoreAlipayInputPieceLogEntity log =
                    mtStoreAlipayInputPieceLogService.getOne(Wrappers.<MtStoreAlipayInputPieceLogEntity>lambdaQuery()
                            .eq(MtStoreAlipayInputPieceLogEntity::getOrderId, orderId));

            if (!Objects.equals(external_id, log.getExternalId())) {
                return "fail";
            }

            //保存日志修改状态，删除以前的失败日志
            log.setNotifyId(notifyId);
            log.setUtcTimestamp(utcTimestamp);
            log.setMsgMethod(msgMethod);
            log.setAppId(appId);
            log.setMsgType(msgType);
            log.setMsgAppId(msgAppId);
            log.setVersion(version);
            log.setBizContent(bizContent);
            log.setInformSign(sign);
            log.setSignType(signType);
            log.setEncryptType(encryptType);
            log.setCharset(charset);
            log.setNotifyType(notifyType);
            log.setNotifyTime(notifyTime);
            log.setAuthAppId(authAppId);
            log.setReason(reason);
            log.setState(INCOMING_ITEMS_ARE_ABNORMAL);
            mtStoreAlipayInputPieceLogService.saveOrUpdate(log);

        } catch (Exception e) {
            log.error("直付通/服务商二级商户进件拒绝消息处理失败：{}", e.getMessage(),e);
            throw new BeanCreationException(e.getMessage());
        }
            /*
            幂等处理
            由于消息存在重试机制（见投递重试策略），同一笔消息（相同 notify_id）可能多次发送（网络原因、商家服务器原因、或者商家接收处理成功但并未按要求返回 success 字符串等），消息接收方需要对同一个 notifyId 的多次消息投递实现幂等处理。若之前相同的 notify_id 已处理成功直接返回 success 字符串即可。
             */
        return "success";
    }

    /**
     * @param orderId
     * @param externalId
     * @return top.lidee.framework.result.ResponseResult
     * @description 直付通/服务商二级商户入驻进度查询
     * @author zhangyiheng
     * @date 2024/9/30 14:11
     */
    @Override
    public ResponseResult progressInquiry(String orderId, String externalId) {
        try {
            if (StrUtil.isAllBlank(orderId, externalId)) {
                return ResponseResult.errorResult(CommonExceptionEnum.PARAM_ERROR);
            }

            AntMerchantExpandIndirectZftorderQueryRequest request = new AntMerchantExpandIndirectZftorderQueryRequest();
            request.setBizContent("{" +
                    "  \"order_id\":\"" + orderId + "\"," +
                    "  \"external_id\":\"" + externalId + "\"" +
                    "}");

            AntMerchantExpandIndirectZftorderQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                System.out.println("调用成功");
                String code = response.getCode();
                //成功
                if (Objects.equals(code, "10000")) {
                    //获取结果并返回
                    List<ZftSubMerchantOrder> orders = response.getOrders();

                    return ResponseResult.okResult(orders);
                } else {
                    //失败
                    String subMsg = response.getSubMsg();
                    return ResponseResult.errorResult(Integer.parseInt(code), subMsg);
                }

            } else {
                return ResponseResult.errorResult(CommonExceptionEnum.LIMIT_ERROR);
            }
        } catch (Exception e) {
            log.error("直付通/服务商二级商户入驻进度查询出错：{}", e.getMessage(),e);
            throw new BeanCreationException(e.getMessage());
        }
    }

}
